#!/usr/bin/python
# -*- coding: utf-8 -*-

#This file is part of pyLot library.
#
# pyLot is free software: you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# pyLot is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with pyLot.  If not, see <http://www.gnu.org/licenses/>.

__author__ = u'Pierre Puiseux, Guillaume Baty'
__copyright__ = u"Copyright 2011-2012 (C) andheo, Université de Pau et des Pays de l'Adour"
__credits__ = [u'Pierre Puiseux', u'Guillaume Baty']
__license__ = "GNU Lesser General Public License"

__all__ = [
           'ENCODING',
           'LANG',
           'LEVELS',
           'cpu_count',
           'error',
           'uprint',
           'repr_unicode',
           'clean_memory',
           ]

import os
import sys
import gc
import locale
import traceback

LANG, ENCODING = locale.getdefaultlocale()
ENCODING = locale.getpreferredencoding()

if isinstance(ENCODING, str):
  ENCODING = ENCODING.decode(ENCODING)
else :
  ENCODING = locale.getdefaultlocale()[1]
  if isinstance(ENCODING, str):
    ENCODING = ENCODING.decode(ENCODING)
  else :
    ENCODING = u'UTF-8'

if isinstance(LANG, str):
  LANG = LANG.decode(ENCODING)
else :
  LANG = u'en'

LEVELS = [u'user', u'devel', u'expert']

def error(unicode_str):
  return unicode_str.encode(ENCODING, u'replace')

def clean_memory():
  gc.collect()
#  res = traceback.extract_stack(limit=2)[0]
#  print 'collect %s objects. Clean called from ...' % gc.collect()
#  print '  - func:', res[0]
#  print '  - line:', res[1]
#  print '  - file:', res[2]

def uprint (*args, **kargs):
  u""" like python 3 print methods.
  all types are supported. 
  unicode is encoded before being printed.
  """
  try :
    stream = kargs['file']
  except KeyError :
    stream = sys.stdout

  try :
    end = kargs['end']
  except KeyError :
    end = ''

  for arg in args :
    if isinstance(arg, unicode):
      print arg.encode(ENCODING, 'replace'),
    else :
      print arg,
  if end :
    print end,

def repr_unicode(s, encoding=ENCODING):

  try :
    return s._unicode_repr_()
  except AttributeError :
    pass

  if isinstance(s, unicode):
    if u"'" in s and u'"' not in s :
      newu = s.replace(u'"', u'\\"')
      newu = u'u"%s"' % newu
    else :
      newu = s.replace(u"'", u"\\'")
      newu = u"u'%s'" % newu

    try :
      new = newu.encode(encoding)
    except UnicodeEncodeError :
      return repr(s)
    else :
      return new

  elif isinstance(s, (list, set, tuple)):
    news = []
    datatype = type(s)
    for value in s:
      news.append(repr_unicode(value, encoding))

    try:
      test_lst = datatype([1])
      before, after = repr(test_lst).split(repr(test_lst[0]))
      # use a new datatype object to handle tricky cases like
      # StringList([1]) -> StringList([u'1'])
    except :
      return repr(s)
    else :
      return '%s%s%s' % (before, ', '.join(news), after)

  elif isinstance(s, dict):
    keys = []
    values = []
    for k, v in s.items():
      values.append(repr_unicode(k, encoding))
      keys.append(repr_unicode(v, encoding))
    news = []
    for i in range(len(keys)) :
      news.append('%s:%s' % (keys[i], values[i]))
    return '{%s}' % (', '.join(news))
  else :
    return repr(s)

def cpu_count():
  u"""
  Returns the number of CPUs in the system
  Imported from python2.6 multiprocessing module
  """
  # TODO: report bug os.sysconf doesn't support unicode
  if sys.platform == u'win32':
    try:
      num = int(os.environ[u'NUMBER_OF_PROCESSORS'])
    except (ValueError, KeyError):
      num = 0
  elif u'bsd' in sys.platform or sys.platform == u'darwin':
    try:
      num = int(os.popen('sysctl -n hw.ncpu').read())
    except ValueError:
      num = 0
    except IOError:
      num = 1
  else:
    try:
      num = os.sysconf('SC_NPROCESSORS_ONLN')
    except (ValueError, OSError, AttributeError):
      num = 0
  if num >= 1:
    return num
  else:
    raise NotImplementedError(error(u'cannot determine number of cpus'))
